package com.nowcoder.topic.trie.middle;

import java.util.ArrayList;
import java.util.HashSet;

/**
 * NC378 两数最大异或值
 * @author d3y1
 */
public class NC378 {
    // 最高数位为30(0-30) -> 31位+1位符号位=32位
    private final int HIGH_BIT = 30;

    /**
     * 代码中的类名、方法名、参数名已经指定，请勿修改，直接返回方法规定的值即可
     *
     * 相似 -> ZJ26 异或 [nowcoder]
     *
     * @param array int整型一维数组
     * @return int整型
     */
    public int maxXOR (ArrayList<Integer> array) {
        // return solution1(array);
        // return solution11(array);
        // return solution2(array);
        // return solution3(array);
        return solution33(array);
    }

    /**
     * 位运算: 异或
     *
     * 双重循环遍历
     *
     * @param array
     * @return
     */
    private int solution1(ArrayList<Integer> array){
        int n = array.size();
        int max = 0;
        int xor;
        for(int i=0; i<n; i++){
            for(int j=i+1; j<n; j++){
                xor = array.get(i)^array.get(j);
                max = Math.max(max, xor);
            }
        }

        return max;
    }

    /**
     * 位运算: 异或
     *
     * 双重循环遍历(哈希优化)
     *
     * @param array
     * @return
     */
    private int solution11(ArrayList<Integer> array){
        HashSet<Integer> set = new HashSet<>();
        for(int val: array){
            set.add(val);
        }

        ArrayList<Integer> distinct = new ArrayList<>(set);
        int size = distinct.size();
        int max = 0;
        int xor;
        for(int i=0; i<size; i++){
            for(int j=i+1; j<size; j++){
                xor = array.get(i)^array.get(j);
                max = Math.max(max, xor);
            }
        }

        return max;
    }

    /**
     * 位运算 + 哈希
     *
     * pre_k() 表示从最高位(第30位)开始的前k位
     * a_i a_j 表示某两个选择的数
     * xor     表示最终异或结果(从高位到低位,依次确定,优先置1)
     *
     * pre_k(xor) = pre_k(a_i) ^ pre_k(a_j)
     * => pre_k(a_j) = pre_k(xor) ^ pre_k(a_i)
     *
     * xor当前数位优先置1(从高位到低位), pre_k(xor)为已知
     * 因此我们先将所有的pre_k(a_j)加入哈希表existed中, 再枚举校验是否存在某个数a_i, 使得pre_k(xor)^pre_k(a_i)恰好出现在existed中.
     *
     * 如果可以找到上面的a_i, 则当前数位可以为1, 否则当前数位只能为0.
     *
     * @param array
     * @return
     */
    private int solution2(ArrayList<Integer> array){
        int xor = 0;
        HashSet<Integer> existed = new HashSet<>();
        // 从高位到低位 依次确定
        for(int i=HIGH_BIT; i>=0; i--){
            existed.clear();
            for(int val: array){
                // pre_k(a_j) val前k位 k=HIGH_BIT-i+1
                existed.add(val>>i);
            }

            // 当前数位优先置1, 此处xor即pre_k(xor) k=HIGH_BIT-i+1
            // xor = xor*2+1;
            xor = (xor<<1)+1;
            boolean found = false;
            for(int val: array){
                // 表示当前数位可以为1 <- 校验pre_k(xor)^pre_k(a_i)
                if(existed.contains(xor^(val>>i))){
                    found = true;
                    break;
                }
            }

            // 未找到 -> 表示当前数位不可为1, 减1置0
            if(!found){
                xor = xor-1;
            }
        }

        return xor;
    }

    /**
     * 字典树
     * @param array
     * @return
     */
    private int solution3(ArrayList<Integer> array){
        Trie trie = new Trie();
        HashSet<Integer> set = new HashSet<>();
        for(int val: array){
            if(!set.contains(val)){
                set.add(val);
                trie.insert(val);
            }
        }

        int max = 0;
        int xor;
        for(int val: set){
            xor = trie.query(val);
            max = Math.max(max, xor);
        }

        return max;
    }

    /**
     * 字典树: 优化
     * @param array
     * @return
     */
    private int solution33(ArrayList<Integer> array){
        Trie trie = new Trie();
        HashSet<Integer> set = new HashSet<>();
        int max = 0;
        int xor;
        for(int val: array){
            if(!set.contains(val)){
                set.add(val);
                trie.insert(val);
                xor = trie.query(val);
                max = Math.max(max, xor);
            }
        }

        return max;
    }

    /**
     * 字典树 Trie
     */
    private class Trie {
        Trie[] children = new Trie[2];

        /**
         * 新增
         * @param val
         */
        private void insert(int val){
            Trie curr = this;
            for(int j=HIGH_BIT; j>=0; j--){
                int bit = (val>>j)&1;
                if(curr.children[bit] == null){
                    curr.children[bit] = new Trie();
                }
                curr = curr.children[bit];
            }
        }

        /**
         * 查询: 获取当前数val的最大异或值
         * @param val
         * @return
         */
        private int query(int val){
            Trie curr = this;
            int xor = 0;
            for(int j=HIGH_BIT; j>=0; j--){
                int bit = (val>>j)&1;
                if(curr.children[bit^1] != null){
                    xor |= (1<<j);
                    curr = curr.children[bit^1];
                }else{
                    curr = curr.children[bit];
                }
            }

            return xor;
        }
    }
}